~S44PLAY.Xのココがポイント~ 1.プレステのCDXAな音声データ 鎌田 誠

はじめに
 S44PLAY.X は、X680x0 の内蔵音源だけでステレオの PCM データをステレオで 再生するプログラムです。ADPCM 音源を一切使っておらず、FM 音源だけで 1 チ ャンネル(モノラル)または 2 チャンネル(ステレオ)の PCM 音源をエミュレ ートすることができます。ダイナミックレンジは狭いものの、モノラル再生なら ば ADPCM 音源よりもかなり音質が良く、マシンのパワーや使い方次第でステレ オでも聴ける音を出せます。S44PLAY.X の再生エンジンは、ゲーム『あの、素晴 らしい  をもう一度』のオープニングにも組み込まれました。  S44PLAY.X は当初は激光電脳倶楽部 VOL.6(1999 年 2 月)の企画として開発 されたものですが、VOL.7 の段階で音質が良くなり、ご好評をいただいたので、 調子に乗ってバージョンアップを続けています。技術的にも、サイズ的にも、こ れだけの規模のプログラムを時間をかけて作ってきたのですから、解説しなきゃ もったいないですよね。しかし、とても簡単に説明できるような規模ではなくな ってしまったので、小分けにして解説したいと思います。S44PLAY.X が単なるス テレオ再生ソフトではないことを理解していただければ幸いです。  S44PLAY.X による PCM の再生方法の技術的なことについては、とりあえず激 光電脳倶楽部 VOL.6 と VOL.7 の該当記事を見ていただくとして、今回は、新た にデコードできるようになった PlayStation 用のソフトに入っている CDXA 方 式の圧縮音声データのフォーマットについて解説します。
CD-ROM のセクタ
 CD(Compact Disc)の論理的なセクタのサイズは、普通は最大で 2352 バイト です。これは 1 サンプリングあたり 16 ビット(2 バイト)× 2 チャンネルで 44.1kHz の PCM データを 1/75 秒ぶんだけ記録できる容量です(2×2×44100÷ 75=2352)。CD ショップで売られている普通の音楽 CD は、1 セクタに 1/75 秒ぶんの音が記録されています。このように CD に記録された音の情報を CDDA (Compact Disc Digital Audio)と呼びます。  CD-ROM(Compact Disc Read Only Memory)版の電脳倶楽部は幾つかのトラッ クに分かれています。先頭のトラックがデータトラックで、ここに ISO9660 と いう規格で定められたフォーマットでファイルシステム(ファイルやディレクト リの集まり)が記録されています。残りは音楽トラック(CDDA)です。CDDA は 前述の通り 1 セクタあたり 2352 バイト目一杯使っていますが、データトラッ クは 2352 バイトの中の 2048 バイトが情報の本体で、残りはエラー訂正用に使 われています。  CD-ROM は汚れや傷が付くことがあるので、2352 バイトの情報が常にすべて正 確に読み出せるとは限りません。CDDA ならば読み出されたデータが少しくらい 間違っていてもアナログ的に修復されてしまったり僅かなノイズになる程度で大 きな問題にはなりませんが、コンピュータで扱うデータについては僅かでも間違 っていると困ります。そこで、データトラックは 2352 バイトのセクタの中の 2048 バイトにデータの本体を置き、残りの領域はデータの本体が間違って読み 出されてしまったときにそれを修復するための情報が記録されるのです(物理的 にメディアを修復することはできないので、論理的に修復するという意味です)。
CDXA とは
 コンピュータが扱うデータの中にも、「多少の間違いは無視して構わないから とにかくに大量のデータを詰め込みたい」という場合があります。画像(動画と 静止画)や音声のデータがそうです。  データの管理のしやすさを考えれば、画像や音声のデータもデータトラックの 中に置いてファイルとして検索できるようになっているべきです。そこで、それ らのデータはデータトラックの中で、部分的にセクタのサイズを 2048 バイトよ りも大きくして詰め込むことにします。このように、1 つのデータトラックの中 でセクタのサイズを用途に応じて変化させることができる記録方式として、 CD-ROM XA、略して CDXA(Compact Disc eXtended Architecture)というものが あります。  ここでは、データの本体が 2048 バイトよりも大きなセクタに格納されている ファイルを「CDXA ファイル」と呼ぶことにします。
PlayStation の場合
 PlayStation 用のソフトは CD-ROM で供給されています。記録面が真っ黒なの でちょっと異様に思われますが、普通の CD-ROM と同じものです。PlayStation 用の CD-ROM では CDXA が採用されており、ムービーや台詞のデータのファイル (主に拡張子が .STR や .XA のもの)のデータの本体が入っているセクタのサ イズは 2048 バイトよりも大きくなっています。そのため、それらのファイルを X680x0 で普通のファイルと同じように読み出そうとするとエラーになってしま います。  CDXA でサイズが 2048 バイトよりも大きいセクタを X680x0 で読み出すには、 Human(と CD-ROM デバイスドライバ)で構成されるファイルシステムを媒介せ ずに、自前で SCSI コマンドを発行して、CD-ROM に記録されているデータを直 接読み出さなければなりません。ファイルシステムが使えないのでディレクトリ の検索も自前で行わなければならず、少々面倒です。
PlayStation の CDXA ファイルの音声セクタのフォーマット
 PlayStation の CDXA ファイルの音声セクタには、実質 2304 バイトの音声デ ータが入っています。CD-ROM ドライブのモードを YellowBook Mode1(2048 バ イト/セクタ)にしてディレクトリを辿って音声データの本体にたどり着いたら、 CD-ROM ドライブのモードを YellowBook Mode2(2336 バイト/セクタ)に切り替 えてデータの本体をヘッダごと読み出します。読み出された音声データは一種の ADPCM 方式で圧縮されているので、デコードして PCM に変換しなければ PCM デ ータとして再生することはできません。  それでは、PlayStation の CDXA ファイルの音声セクタの記録方式を、外側か ら順に解体していきましょう。 ● 2336 バイトのサイズで読み出されたセクタの構造 ┌──────┬──────┬────────────┐ │ オフセット │長さ(バイト)│ 内容 │ ├──────┼──────┼────────────┤ │ 0 │ 4 │ヘッダ │ │ 4 │ 4 │ヘッダ │ │ 8 │ 2304 │音声データの本体 │ │ 2312 │ 24 │あまり │ └──────┴──────┴────────────┘  ヘッダが 2 つ書いてあるのは、同じものが 2 つ並んでいるからです。 ●ヘッダの内容 ┌──────┬──────┬────────────┐ │ オフセット │長さ(バイト)│ 内容 │ ├──────┼──────┼────────────┤ │ 0 │ 1 │? │ │ 1 │ 1 │トラック番号 │ │ 2 │ 1 │データの種類 │ │ 3 │ 1 │モード │ └──────┴──────┴────────────┘ ●トラック番号  これは CD-ROM 全体のトラックとは関係なく、CDXA ファイルの中でのデータ の通し番号です。1 つの CDXA ファイルの中に複数のデータが入っている場合に、 その番号が書いてあります。ムービーのファイルの音声トラックの番号は、$01 である場合が多いようです。 ●データの種類  ムービーのファイルでは、画像が入っているセクタの並びのところどころに音 声が入っているセクタが挟まっています。今回 S44PLAY.X でデコードできるよ うになった音声が入っているセクタのデータの種類は $64 です。画像が入って いるセクタでは、データの種類が $42 や $48 になっていました。 ●モード  データの種類が $64 の音声のセクタは、チャンネル数とサンプリング周波数 によって 4 つのモードがあります。 モードのビット0(チャンネル数) 0 = モノラル 1 = ステレオ モードのビット2(サンプリング周波数) 0 = 37.8kHz 1 = 18.9kHz ●音声データの本体  音声データの本体の構造を説明するのは、はっきり言って、かなり厄介です。 CDXA の ADPCM は、X680x0 の ADPCM の圧縮方式よりもかなり複雑なのです。 「知りたい人は S44PLAY.X のソースリストを見て下さい」と言いたいところで すが、とりあえず説明することにしましょう。そのために書き始めたのですから。  まず、音声データの本体は、1 個が 128 バイトのデータのかたまりを 18 個 並べた構造をしています。この 128 バイトのデータのかたまりをサウンドグル ープと呼ぶことにします。CDXA の音声データの 1 セクタには、サウンドグルー プが 18 個入っています。 1セクタあたり 128バイト×18サウンドグループ=2304バイト  18 個のサウンドグループは、セクタの先頭に近い側から順に、時間の順序で 並んでいます。  1 つのサウンドグループの中には、16 バイトのフィルタ・レンジ情報と、符 号つき 4 ビット整数の ADPCM データが 224 個、この順序で入っています。224 個の ADPCM データは、モノラルならば 224 サンプル、ステレオならば 112 サ ンプル分のデータです。 1サウンドグループあたり 16バイト+0.5バイト×224サンプル=128バイト  例えば、37.8kHz のステレオの CDXA データの場合、 112サンプル×18サウンドグループ÷37800サンプル/秒=4/75秒 ですから、1 セクタに 4/75 秒、つまり CDDA の 4 倍の密度で音声を記録でき ることになります。  1 つのサウンドグループの中に 4 ビットの ADPCM データが 224 個入ってい ると書きましたが、この 224 個の ADPCM データをさらに 28 個ずつ 8 つのユ ニットに分類します。ユニットの番号は時間の順序で 0~7 を振ることにします。 ステレオのデータの場合は、ユニット 0,2,4,6 が左のチャンネル、ユニット 1,3,5,7 が右のチャンネルのデータになります。 1ユニットあたり 224サンプル÷8ユニット=28サンプル  224 個の ADPCM データを時間の順序でユニット 0 からユニット 7 に分類し ましたが、これはデータの順序にはなっていません。データの順序を 1 バイト ずつ表記すると次のようになります。 サウンドグループの先頭からのオフセット | 16 ユニット1のADPCMデータ( 0)×16+ユニット0のADPCMデータ( 0) 17 ユニット3のADPCMデータ( 0)×16+ユニット2のADPCMデータ( 0) 18 ユニット5のADPCMデータ( 0)×16+ユニット4のADPCMデータ( 0) 19 ユニット7のADPCMデータ( 0)×16+ユニット6のADPCMデータ( 0) 20 ユニット1のADPCMデータ( 1)×16+ユニット0のADPCMデータ( 1) 21 ユニット3のADPCMデータ( 1)×16+ユニット2のADPCMデータ( 1) 22 ユニット5のADPCMデータ( 1)×16+ユニット4のADPCMデータ( 1) 23 ユニット7のADPCMデータ( 1)×16+ユニット6のADPCMデータ( 1) : : 120 ユニット1のADPCMデータ(26)×16+ユニット0のADPCMデータ(26) 121 ユニット3のADPCMデータ(26)×16+ユニット2のADPCMデータ(26) 122 ユニット5のADPCMデータ(26)×16+ユニット4のADPCMデータ(26) 123 ユニット7のADPCMデータ(26)×16+ユニット6のADPCMデータ(26) 124 ユニット1のADPCMデータ(27)×16+ユニット0のADPCMデータ(27) 125 ユニット3のADPCMデータ(27)×16+ユニット2のADPCMデータ(27) 126 ユニット5のADPCMデータ(27)×16+ユニット4のADPCMデータ(27) 127 ユニット7のADPCMデータ(27)×16+ユニット6のADPCMデータ(27)  最後に、各サウンドグループの先頭にある 16 バイトのレンジ・フィルタ情報 の構造を示します。16 バイトの領域が割り当てられていますが、実質的には 8 バイトしか使っていません。普通は 16 バイトの領域の中央の 8 バイトを使い ます。8 組のレンジ・フィルタ情報が 8 つのユニットに対応しています。 サウンドグループの先頭からのオフセット | 0 ユニット0のフィルタ番号×16+ユニット0のレンジ 1 ユニット1のフィルタ番号×16+ユニット1のレンジ 2 ユニット2のフィルタ番号×16+ユニット2のレンジ 3 ユニット3のフィルタ番号×16+ユニット3のレンジ 4 ユニット0のフィルタ番号×16+ユニット0のレンジ 5 ユニット1のフィルタ番号×16+ユニット1のレンジ 6 ユニット2のフィルタ番号×16+ユニット2のレンジ 7 ユニット3のフィルタ番号×16+ユニット3のレンジ 8 ユニット4のフィルタ番号×16+ユニット4のレンジ 9 ユニット5のフィルタ番号×16+ユニット5のレンジ 10 ユニット6のフィルタ番号×16+ユニット6のレンジ 11 ユニット7のフィルタ番号×16+ユニット7のレンジ 12 ユニット4のフィルタ番号×16+ユニット4のレンジ 13 ユニット5のフィルタ番号×16+ユニット5のレンジ 14 ユニット6のフィルタ番号×16+ユニット6のレンジ 15 ユニット7のフィルタ番号×16+ユニット7のレンジ  以上で CDXA ファイルのセクタの内容がすべて示されました。後はどうやって CDXA のセクタを PCM にデコードするかです。  ここでは、時間の順序で n 番目の PCM データを pcm(n) で表すことにします。 次の式が、CDXA ファイルの ADPCM データから PCM への変換(デコード)を行 う式です。 ┌──────────────────────────┐ │ │ │ pcm(n)=(d<<(12-r))+pcm(n-1)*C1(f)+pcm(n-2)*C2(f) │ │ │ └──────────────────────────┘  ここで、pcm(n-1) は pcm(n) の 1 つ前の PCM データ、pcm(n-2) は pcm(n) の 2 つ前の PCM データです(前のデータがなければ 0 とします)。C1(0)~ C1(3) と C2(0)~C2(3) はそれぞれ 1 つ前と 2 つ前の PCM データに掛ける定 数です。d と r と f は CDXA ファイルから得られる情報で、それぞれ ADPCM データ(符号つき 4 ビット)、レンジ(0~12)、フィルタの番号(0~3)です。  C1(0)~C1(3) と C2(0)~C2(3) は次のような定数です。 C1(0)~C1(3) C1(0)=0.0 ($0000.0000) C1(1)=0.9375 ($0000.F000) C1(2)=1.796875 ($0001.CC00) C1(3)=1.53125 ($0001.8800) C2(0)~C2(3) C2(0)=0.0 ($0000.0000) C2(1)=0.0 ($0000.0000) C2(2)=-0.8125 ($FFFF.3000) C2(3)=-0.859375 ($FFFF.2400)  レンジとフィルタの番号は、前述のようにユニット毎に与えられています。1 つのユニットの中の ADPCM データは時間的に連続しているので、レンジとフィ ルタの番号は、時間的に局所的な範囲内での PCM データの特性を示していると 言えます。  上の式で求められた pcm(n) の結果を符号つき 16 ビット整数の範囲(-32768 ~32767)でクリッピングすれば、デコードされた符号つき 16 ビットの PCM デ ータが得られます。
今回はここまで
 こんな下手な説明で理解するのは大変かも知れません。どうしても理解したい 人は…やはりソースリストを見て下さい(爆)。  本当はディレクトリを辿って CDXA ファイルを検索するところも書きたかった のですが、時間がなくなってしまったので今回はパス。 (EOF)